import json
import os
import PySimpleGUI as sg
import requests.exceptions
from requests.api import *
from requests.auth import HTTPDigestAuth

text = '''使用说明：
headers框中添加请求头，格式为key:value，每个键值对为一行。
settings框中添加设置信息，格式为key:value，每个键值对为一行，
timeout:1   设置接口超时时间，系统默认3秒
files:文件路径  设置上传文件
allow_redirects:True    默认为True, 允许自动跟随重定向
verify:True 默认为True，启用 SSL 证书验证
uesrname:xxx换行password:xxx    摘要身份验证的用户名和密码
cookies框中添加cookie信息，格式为key:value
中框中添加请求体，格式为&name=jack&age=18，或者{"name":"jack","age":"18"}
qq:2837015586
'''

sg.set_options(font=("Arial Bold", 12))
sg.theme("DefaultNoMoreNagging")

menu = [
    ["&File", ["&save"]],
    ["&Help", ["&help"]],
    ["&Tool", ["&contrast"]],
]
layout = [
    [sg.Menu(menu, key="menu")],
    [sg.Combo(["GET", "POST", "PUT", "PATCH", "DELETE", "OPTIONS"], default_value="GET", size=(10, 10),
              readonly=False, font=("宋体"), key='method')] +
    [sg.In(key="url", size=(105, 115), border_width=2, enable_events=True)] +
    [sg.B("send", size=(8, 1), key="send")] +
    [sg.B("clear", size=(8, 1), key="clear")],
    [sg.T("HEADERS", justification="left", size=(60, 1))] + [sg.T("SETTINGS", size=(54, 1))] + [
        sg.T("COOKIES", justification="right")],
    [sg.ML(key="headers", size=(45, 5), justification="left")] + [
        sg.ML(key="settings", size=(45, 5))] + [sg.ML(key="cookies", size=(45, 5), justification="left")],
    [sg.Combo(["json", "xml", "html", "text", "form-data", "x-www-form-urlencoded"], default_value="text", size=(9, 9),
              key="f1")],
    [sg.ML(key="params", autoscroll=False, size=(156, 10))],
    [sg.Combo(["json", "xml", "html", "text"], default_value="json", size=(9, 9), key="f2")],
    [sg.ML(key="output", autoscroll=False, size=(156, 20))]
]

window = sg.Window('接口测试工具', layout, return_keyboard_events=True,
                   grab_anywhere=True, resizable=True).Finalize()
window.Maximize()

headers = {}
cookies = {}
params = {}
settings = {}
timeout = 3
files = {}
allow_redirects = {}
verify = {}
username = ""
password = ""
formatted_json_response_content = ""


def getHeaders():
    if values["headers"]:
        if "\n" in values["headers"]:
            strHeaders = values["headers"].strip().split("\n")
            headers = {i.split(":")[0]: i.split(":")[-1] for i in strHeaders}
            return headers
        else:
            k, v = values["headers"].strip().split(":")
            headers = {k: v}
            return headers


def getSettings():
    if values["settings"] != "":
        if "\n" in values["settings"]:
            strSettings = values["settings"].strip().split("\n")
            settings = {i.split(":")[0]: i.split(":")[-1] for i in strSettings}
            return settings
        if "\n" not in values["settings"]:
            k, v = values["settings"].strip().split(":")
            settings = {k: v}
            return settings


def getCookies():
    if values["cookies"]:
        if "\n" in values["cookies"]:
            strCookies = values["cookies"].strip().split("\n")
            cookies = {i.split(":")[0]: i.split(":")[-1] for i in strCookies}
            return cookies
        else:
            k, v = values["cookies"].strip().split(":")
            cookies = {k: v}
            return cookies


def getParams():
    if values["params"] != "":
        if values["params"] and "\n" in values["params"]:
            strParams = values["params"].strip().split("\n")
            params = {i.split(":")[0]: i.split(":")[-1] for i in strParams}
            return params

        if "&" in values["params"]:
            strParams = values["params"].replace("&", ",").replace("=", ":").strip("").split(",")
            params = {i[:i.find(":")]: i[i.find(":") + 1:] for i in strParams}
            return params


def postParams():
    if values["params"] != "":
        if values["params"] and "\n" in values["params"]:
            strParams = values["params"].strip().split("\n")
            params = {i.split(":")[0]: i.split(":")[-1] for i in strParams}
            return params

        if values["params"][0] == "{" and values["params"][-1] == "}":
            params = eval(values["params"])
            return params

        if "&" in values["params"]:
            strParams = values["params"].replace("&", ",").replace("=", ":").strip("").split(",")
            params = {i[:i.find(":")]: i[i.find(":") + 1:] for i in strParams}
            return params


def clearAll():
    window["url"].update("")
    window["headers"].update("")
    window["settings"].update("")
    window["cookies"].update("")
    window["params"].update("")
    window["output"].update("")


def setting_headers():
    global headers
    if values["f1"] == "text":
        headers = {"Content-Type": "text/plain"}
    if values["f1"] == "html":
        headers = {"Content-Type": "text/html"}
    if values["f1"] == "xml":
        headers = {"Content-Type": "application/xml"}
    if values["f1"] == "json":
        headers = {"Content-Type": "application/json"}
    if values["f1"] == "form-data":
        headers = {"Content-Type": "multipart/form-data"}
    if values["f1"] == "x-www-form-urlencoded":
        headers = {"Content-Type": "application/x-www-form-urlencoded"}
    return headers


def printResponse():
    global response, headers, cookies, params, timeout, files, allow_redirects, verify, username, password, formatted_json_response_content

    # 获取请求方法
    request_method = values['method'].lower()

    if request_method == "get":
        params = getParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}

        response = get(url=values["url"], headers=headers, cookies=cookies, params=params
                       , timeout=timeout, files=files, allow_redirects=allow_redirects
                       , verify=verify, auth=HTTPDigestAuth(username, password))

    if request_method == "post":
        data = postParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}
        response = post(url=values["url"], headers=headers, cookies=cookies, data=data
                        , timeout=timeout, allow_redirects=allow_redirects, verify=verify
                        , files=files, auth=HTTPDigestAuth(username, password))

    if request_method == "put":
        data = getParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}
        response = put(url=values["url"], headers=headers, cookies=cookies, data=data
                       , timeout=timeout, allow_redirects=allow_redirects, verify=verify
                       , files=files, auth=HTTPDigestAuth(username, password))

    if request_method == "delete":
        data = getParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}
        response = delete(url=values["url"], headers=headers, cookies=cookies, data=data
                          , timeout=timeout, allow_redirects=allow_redirects, verify=verify,
                          files=files, auth=HTTPDigestAuth(username, password))

    if request_method == "patch":
        data = getParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}
        response = patch(url=values["url"], headers=headers, cookies=cookies, data=data
                         , timeout=timeout, allow_redirects=allow_redirects, verify=verify
                         , files=files, auth=HTTPDigestAuth(username, password))

    if request_method == "options":
        data = getParams()
        headers = getHeaders()

        if headers == None:
            headers = setting_headers()
        else:
            if values["f1"] == "text":
                headers["Content-Type"] = "text/plain"
            if values["f1"] == "html":
                headers["Content-Type"] = "text/html"
            if values["f1"] == "xml":
                headers["Content-Type"] = "application/xml"
            if values["f1"] == "json":
                headers["Content-Type"] = "application/json"
            if values["f1"] == "form-data":
                headers["Content-Type"] = "multipart/form-data"
            if values["f1"] == "x-www-form-urlencoded":
                headers["Content-Type"] = "application/x-www-form-urlencoded"

        cookies = getCookies()
        settings = getSettings()

        if settings:
            timeout = settings.get("timeout")
            if timeout:
                timeout = int(timeout)
            allow_redirects = settings.get("allow_redirects")
            allow_redirects = True if allow_redirects == 'True' else False
            verify = settings.get("verify")
            verify = True if verify == 'True' else False
            username = settings.get("username")
            password = settings.get("password")

            filesPath = settings.get("files")
            if filesPath == None:
                files = None
            else:
                files = {"file": open(filesPath, 'rb')}
        response = options(url=values["url"], headers=headers, cookies=cookies, data=data
                           , timeout=timeout, allow_redirects=allow_redirects, verify=verify
                           , files=files, auth=HTTPDigestAuth(username, password))

    if values["f2"] == "text":
        response.headers["Content-Type"] = "text/plain"
    if values["f2"] == "html":
        response.headers["Content-Type"] = "text/html"
    if values["f2"] == "xml":
        response.headers["Content-Type"] = "application/xml"
    if values["f2"] == "json":
        response.headers["Content-Type"] = "application/json"

    # 请求头
    str_headers = '\n'.join([f'{k}：{v}' for k, v in response.request.headers.items()])

    # cookie
    str_cookies = '\n'.join([f'{k}：{v}' for k, v in response.cookies.items()])

    # 响应头
    str_response_headers = '\n'.join([f'{k}：{v}' for k, v in response.headers.items()])

    # 响应报文
    try:

        if values["f2"] == "json":
            response_content = response.json()
            formatted_json_response_content = json.dumps(response_content, indent=4, ensure_ascii=False)

        else:
            formatted_json_response_content = response.content.decode("utf-8")
    except json.JSONDecodeError as e:
        sg.popup("响应内容为空，或json 解析错误，请更换响应格式")
    return f'请求头：\n{str_headers}\n\ncookies：\n{str_cookies}\n\n请求报文：\n{response.request.body}\n\n响应头：\n{str_response_headers}\n\n状态码：{response.status_code}\n\n响应报文：\n{formatted_json_response_content}'


def save(path, filename):
    path = path
    filename = filename
    file_path = os.path.join(path, filename)
    with open(file_path, "w", encoding="UTF-8") as file:
        file.write(f'''
请求方法：   {values['method']}
请求路径：   {values['url']}
headers:   {headers}
cookie :   {cookies}
settings:  {settings}
{response}
        ''')


def open_second_window():
    layout2 = [
        [sg.ML(key="one", size=(50, 20))] +
        [sg.ML(key="two", size=(50, 20))],
        [sg.B("开始", key="begin")]
    ]
    window2 = sg.Window("对比", layout2)
    while True:
        event1, value1 = window2.read()
        if event1 == None or event1 == sg.WINDOW_CLOSED:
            break
        if event1 == "begin":
            if value1["one"] == value1["two"]:
                sg.popup("对比成功")
            else:
                sg.popup("对比失败")


if __name__ == '__main__':

    while True:

        event, values = window.read()

        if event == None or event == sg.WINDOW_CLOSED:
            break
        if event == "save":
            try:
                response = printResponse()
                if response:
                    path = sg.popup_get_text("请输入文件路径：")
                    message = sg.popup_get_text("请输入文件名：")
                    save(path, message)
            except Exception as e:
                sg.popup(e)

        if event == "clear":
            clearAll()
        if event == "help":
            sg.popup(text)
        if event == "contrast":
            open_second_window()
        if event == "send":
            try:
                info = printResponse()
                window["output"].update(value=info)
            except requests.exceptions.MissingSchema as e:
                clearAll()
                sg.popup("缺少协议头")
            except requests.exceptions.InvalidSchema as e:
                clearAll()
                sg.popup("协议头无效")
            except ValueError as e:
                sg.popup("headers或settings或cookie参数有误")
            except FileNotFoundError as e:
                sg.popup("没有这样的文件或目录")
            except requests.exceptions.ConnectTimeout as e:
                sg.popup("请求超时")
            except Exception as e:
                sg.popup(e)
